# -*- coding: utf-8 -*-
import base64
import json
from collections import OrderedDict
from datetime import datetime

import requests
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
from django.conf import settings

from async import async_job
from common.cache import redis_cache
from common.channel.pay import check_channel_order
from common.order import db as order_db
from common.order.model import PAY_STATUS
from common.utils import track_logging
from common.utils.exceptions import ParamError

_LOGGER = track_logging.getLogger(__name__)

APP_CONF = {
    '181203583321': {  # e汇支付  alipay-wap  10-5000  2.5%  witch
        'API_KEY': '66b6a8e9dca348dcbf8ea9ab00a2ef74',
        'gateway': 'https://pay.e100pay.com/api/gateway/payment',
        'query_gateway': 'https://pay.e100pay.com/api/gateway/query',
        'pub_key': """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnWeT7cTZyvRcBEianmb7bEr3G
JDCbc6b78OojbEtt9+e8WrYGVBpOuuasvExweVA4mrSfoNRIuKhF+8tph0ND9Lof
ZFfFbmu3uyJJAs1EiJQ6rF8kwoIGKOGere/1bEHEjUwj5BoMN3hHwML2kahzM+ed
k3/MNiQI/6510ZLdJwIDAQAB
-----END PUBLIC KEY-----""",
        'pri_key': """-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCnWeT7cTZyvRcBEianmb7bEr3GJDCbc6b78OojbEtt9+e8WrYG
VBpOuuasvExweVA4mrSfoNRIuKhF+8tph0ND9LofZFfFbmu3uyJJAs1EiJQ6rF8k
woIGKOGere/1bEHEjUwj5BoMN3hHwML2kahzM+edk3/MNiQI/6510ZLdJwIDAQAB
AoGBAJ8qHWGT5IAuHYH0PHVtAZukcH/SDbTbwzadhGKabgcyH+IBuFu+g6Lbmecx
09WpW8XqRd4Ifb6IeerNt0Iv1qVyXQeW6LEz0lZ6wZPgl63P78isd8cLaAFLD7u+
uH2TXKqjw/U62jVDZqFwVGAxha1zhkmPgkjSREtmLAyELuXxAkEA1gM7s6B7Cq/a
6zBHB3YPJc4kxHhC3SRHXZWA755Xs/PU96yx5w/ylVVxIale1oqulWeWabLN/0tz
eW2MUIdYvwJBAMgvF57sP0UAk8mdtf3OhslAd3LW3NKrojiBUgd1CeXJGHxAM5X6
YbsoMdcomytC5obNnW5IhFiPj6UurYf67ZkCQCNM4TodzG3U1+1XR0AJzzHTMOlf
VNgZNdRP5rafjaPXIlfAGpAcZ00OjNyajVQiB+4I6hyBK81iaqeq1CwsRw0CQC/Q
v82gFITA3Iwd9aiIOj27/kwZ8mkHwhnJGfTaCeEvJYAYPbonMkzoDu+brWSp+DJe
zqnW/HXC5MbJ3X1LfJECPweqY0UXw6PPFeGynpXGbb62zb96Y9CW1qbTPy7N5KCD
dNqUBGeJ87QWhXCj8y0o8rs1oU1+GzX8jNK2TJsapw==
-----END RSA PRIVATE KEY-----""",
    },
}


def _get_api_key(mch_id):
    return APP_CONF[mch_id]['API_KEY']


def _get_gateway(mch_id):
    return APP_CONF[mch_id]['gateway']


def _get_query_gateway(mch_id):
    return APP_CONF[mch_id]['query_gateway']


def _gen_sign(message, the_key):
    key = RSA.importKey(the_key)
    h = SHA256.new(message)
    signer = Signature_pkcs1_v1_5.new(key)
    signature = signer.sign(h)
    return base64.b64encode(signature)


def _get_device_ip(info):
    try:
        extra = json.loads(info['extra'])
    except:
        extra = {}
    user_info = extra.get('user_info', {})
    return user_info.get('device_ip') or '127.0.0.1'


def _get_pay_type(service):
    if service == 'alipay':
        payType = '40'
    return payType


def _build_form(params, gateway):
    html = u"<head><title>loading...</title></head><form id='submit' name='submit' action='" + gateway + "' method='post'>"
    for k, v in params.items():
        html += "<input type='hidden' name='%s' value='%s'/>" % (k, v)
    html += "</form>"
    html += "<script>doc" \
            "ument.forms['submit'].submit();</script>"
    return html


def generate_rsa_sign_str(parameter, api_key):
    s = ''
    key_list = ['Version', 'MchId', 'MchOrderNo', 'PayType', 'Amount', 'OrderTime', 'ClientIp',
                'NotifyUrl']
    order_dict = OrderedDict((k, parameter.get(k)) for k in key_list)
    _LOGGER.info("ehuipay rsa_sign_str order_dict is: %s", order_dict)
    for k in order_dict:
        s += '%s|' % (parameter[k].encode('utf8'))
    s += str(api_key)
    _LOGGER.info("ehuipay sign is: %s", s)
    return s


def generate_query_request_rsa_sign_str(parameter, api_key):
    s = ''
    key_list = ['Version', 'MchId', 'MchOrderNo']
    order_dict = OrderedDict((k, parameter.get(k)) for k in key_list)
    _LOGGER.info("ehuipay query_request_rsa_sign_str order_dict is: %s", order_dict)
    for k in order_dict:
        s += '%s|' % (parameter[k].encode('utf8'))
    s += str(api_key)
    _LOGGER.info("ehuipay query_request_sign is: %s", s)
    return s


def generate_notify_rsa_sign_str(parameter, api_key):
    s = ''
    key_list = ['Version', 'MchId', 'MchOrderNo', 'OrderId', 'PayAmount', 'PayResult', 'PayMessage']
    order_dict = OrderedDict((k, parameter.get(k)) for k in key_list)
    _LOGGER.info("ehuipay notify_rsa_sign_str order_dict is: %s", order_dict)
    for k in order_dict:
        s += '%s|' % (parameter[k].encode('utf8'))
    s += str(api_key)
    _LOGGER.info("ehuipay notify_sign is: %s", s)
    return s


def generate_query_response_rsa_sign_str(parameter, api_key):
    s = ''
    key_list = ['version', 'mchId', 'mchOrderNo', 'orderId', 'amount']
    order_dict = OrderedDict((k, parameter.get(k)) for k in key_list)
    _LOGGER.info("ehuipay query_response_rsa_sign_str order_dict is: %s", order_dict)
    for k in order_dict:
        s += '%s|' % (parameter[k].encode('utf8'))
    s += str(api_key)
    _LOGGER.info("ehuipay query_response_sign is: %s", s)
    return s


def _get_pri_key(mch_id):
    return APP_CONF[mch_id]['pri_key']


def verify_notify_sign(params, key, api_id):
    sign = params['Sign']
    params.pop('Sign')
    notify_sign = generate_notify_rsa_sign_str(params, key)
    calculated_sign = _gen_sign(notify_sign, _get_pri_key(api_id))
    if sign.lower() != calculated_sign.lower():
        _LOGGER.info("ehuipay notify sign: %s, calculated sign: %s", sign, calculated_sign)
        raise ParamError('sign not pass, data: %s' % params)


def verify_query_response_sign(params, key, api_id):
    sign = params['sign']
    params.pop('sign')
    query_sign = generate_query_response_rsa_sign_str(params, key)
    calculated_sign = _gen_sign(query_sign, _get_pri_key(api_id))
    if sign.lower() != calculated_sign.lower():
        _LOGGER.info("ehuipay query sign: %s, calculated sign: %s", sign, calculated_sign)
        raise ParamError('sign not pass, data: %s' % params)


def create_charge(pay, pay_amount, info):
    service = info.get('service')
    app_id = info['app_id']
    api_key = _get_api_key(app_id)
    parameter_dict = OrderedDict((
        ('Version', '1.0'),
        ('MchId', app_id),
        ('MchOrderNo', str(pay.id)),
        ('PayType', _get_pay_type(service)),
        ('BankCode', ''),
        ('Amount', '%.2f' % pay_amount),
        ('OrderTime', datetime.now().strftime('%Y%m%d%H%M%S')),
        ('ClientIp', _get_device_ip(info)),
        ('NotifyUrl', '{}/pay/api/{}/ehuipay/{}'.format(settings.NOTIFY_PREFIX, settings.NOTIFY_PATH, app_id)),
        ('ReturnUrl', '{}/pay/api/{}/ehuipay/{}'.format(settings.NOTIFY_PREFIX, settings.RETURN_PATH, pay.id)),
        ('remark', 'Charge'),
    ))
    sign_str = generate_rsa_sign_str(parameter_dict, api_key)
    parameter_dict['sign'] = _gen_sign(sign_str, _get_pri_key(app_id))
    _LOGGER.info("ehuipay create_charge requests data: %s", json.dumps(parameter_dict))
    html_text = _build_form(parameter_dict, _get_gateway(app_id))
    _LOGGER.info("ehuipay create_charge create html: %s", html_text)
    cache_id = redis_cache.save_html(pay.id, html_text)
    charge_resp = {
        'charge_info': settings.PAY_CACHE_URL + cache_id,
    }
    return charge_resp


# SUCCESS
def check_notify_sign(request, app_id):
    api_key = _get_api_key(app_id)
    data = dict(request.POST.iteritems())
    _LOGGER.info("ehuipay notify data: %s", data)
    verify_notify_sign(data, api_key, app_id)
    pay_id = data['MchOrderNo']
    if not pay_id:
        _LOGGER.error("fatal error, out_trade_no not exists, data: %s" % data)
        raise ParamError('ehuipay event does not contain pay ID')
    pay = order_db.get_pay(str(pay_id))
    if not pay:
        raise ParamError('pay_id: %s invalid' % pay_id)
    if pay.status != PAY_STATUS.READY:
        raise ParamError('pay %s has been processed' % pay_id)

    mch_id = pay.mch_id
    trade_status = str(data['PayResult'])
    total_fee = float(data['PayAmount'])
    trade_no = data['MchOrderNo']
    extend = {
        'trade_status': trade_status,
        'trade_no': trade_no,
        'total_fee': total_fee
    }
    check_channel_order(pay_id, total_fee, app_id)
    if trade_status == 'SUCCESS' and total_fee > 0.0:
        _LOGGER.info('ehuipay check order success, mch_id:%s pay_id:%s' % (mch_id, pay_id))
        order_db.add_pay_success(mch_id, pay_id, total_fee, trade_no, extend)
        # async notify
        async_job.notify_mch(pay_id)


def query_charge(pay_order, app_id):
    ''' 查询订单 '''
    pay_id = pay_order.id
    api_key = _get_api_key(app_id)
    parameter_dict = OrderedDict((
        ('Version', '1.0'),
        ('MchId', app_id),
        ('MchOrderNo', str(pay_id)),
    ))
    sign_str = generate_query_request_rsa_sign_str(parameter_dict, api_key)
    parameter_dict['sign'] = _gen_sign(sign_str, _get_pri_key(app_id))
    _LOGGER.info("ehuipay query req data: %s", json.dumps(parameter_dict))
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_get_query_gateway(app_id), data=parameter_dict, headers=headers, timeout=5)
    _LOGGER.info("ehuipay query rsp code: %s, data: %s", response.status_code, response.text)
    if response.status_code == 200:
        data = json.loads(response.text)
        _LOGGER.info("ehuipay query response body: %s", data)
        verify_query_response_sign(data, api_key, app_id)
        mch_id = pay_order.mch_id
        trade_status = str(data['status'])
        total_fee = float(data['amount'])
        trade_no = data['mchOrderNo']
        extend = {
            'trade_status': trade_status,
            'total_fee': total_fee,
            'trade_no': trade_no,
        }
        if trade_status == '2':
            check_channel_order(pay_id, total_fee, app_id)

            _LOGGER.info('ehuipay query order success, mch_id:%s pay_id:%s' % (mch_id, pay_order.id))
            order_db.add_pay_success(pay_order.mch_id, pay_order.id,
                                     total_fee, trade_no, extend)
            async_job.notify_mch(pay_order.id)
